package com.closer.service.api;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.closer.service.biz.app.dto.*;
import com.closer.service.biz.app.dto.vo.AppVO;
import com.closer.service.biz.user.dto.vo.LoginUserVO;
import com.closer.service.config.ratelimit.RateLimit;
import com.closer.service.config.ratelimit.RateLimitType;
import com.closer.service.support.annotation.AuthCheck;
import com.closer.service.support.common.BaseResponse;
import com.closer.service.support.common.DeleteRequest;
import com.closer.service.support.common.ResultUtils;
import com.closer.service.support.constant.UserConstant;
import com.closer.service.support.exception.ErrorCode;
import com.closer.service.support.exception.ThrowUtils;
import com.mybatisflex.core.paginate.Page;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import com.closer.service.biz.app.service.AppService;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.util.Map;

import static com.closer.service.support.constant.UserConstant.USER_LOGIN_STATE;

/**
 * 应用 控制层。
 *
 * @author closer
 */
@RestController
@RequestMapping("/app")
public class AppController {

    private final AppService appService;

    public AppController(@Autowired AppService appService) {
        this.appService = appService;
    }

    @PostMapping("/add")
    public BaseResponse<Long> addApp(@RequestBody AppAddRequest params, HttpServletRequest  request){
        var loginUser= getLoginUserVO(request);
        var result = appService.addApp(params, loginUser);
        return ResultUtils.success(result);
    }

    @PostMapping("/update")
    public BaseResponse<Boolean> updateApp(@RequestBody AppUpdateRequest params,HttpServletRequest  request){
        var loginUser= getLoginUserVO(request);
        var result = appService.updateApp(params, loginUser);
        return ResultUtils.success(result);
    }

    @PostMapping("/delete")
    public BaseResponse<Boolean> deleteApp(@RequestBody DeleteRequest params, HttpServletRequest  request){
        var loginUser= getLoginUserVO(request);
        var result = appService.delete(params,loginUser);
        return ResultUtils.success(result);
    }

    @GetMapping("/get/vo")
    public BaseResponse<AppVO> getAppVOById( Long id){
        var result = appService.getAppVO(id);
        return ResultUtils.success(result);
    }

    @PostMapping("/my/list/page/vo")
    public BaseResponse<Page<AppVO>> listMyAppVOByPage(@RequestBody AppQueryRequest params, HttpServletRequest  request){
        var loginUser= getLoginUserVO(request);
        var result = appService.getMyAppVOByPage(params, loginUser);
        return ResultUtils.success(result);
    }

    @PostMapping("/good/list/page/vo")
    @Cacheable(
            value = "good_app_page",
            key = "T(com.closer.service.support.utils.CacheKeyUtils).generateKey(#params)",
            condition = "#params.pageNum <= 10"
    )
    public BaseResponse<Page<AppVO>> listGoodAppVOByPage(@RequestBody AppQueryRequest params){
        var result = appService.getGoodAppVOByPage(params);
        return ResultUtils.success(result);
    }

    /**
     * 管理员删除应用
     *
     * @param params 删除请求
     * @return 删除结果
     */
    @PostMapping("/admin/delete")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> deleteAppByAdmin(@RequestBody DeleteRequest params) {
        var result = appService.deleteByAdmin(params);
        return ResultUtils.success(result);
    }

    /**
     * 管理员更新应用
     *
     * @param params 更新请求
     * @return 更新结果
     */
    @PostMapping("/admin/update")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Boolean> updateAppByAdmin(@RequestBody AppAdminUpdateRequest params) {
        var result = appService.updateByAdmin(params);
        return ResultUtils.success(result);
    }

    /**
     * 管理员分页获取应用列表
     *
     * @param params 查询请求
     * @return 应用列表
     */
    @PostMapping("/admin/list/page/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<Page<AppVO>> listAppVOByPageByAdmin(@RequestBody AppQueryRequest params) {

        var result = appService.listAppVOByPageByAdmin(params);
        return ResultUtils.success(result);
    }

    /**
     * 管理员根据 id 获取应用详情
     *
     * @param id 应用 id
     * @return 应用详情
     */
    @GetMapping("/admin/get/vo")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<AppVO> getAppVOByIdByAdmin(long id) {
        var result = appService.getAppVO(id);
        return ResultUtils.success(result);
    }

    @GetMapping(value = "/chat/gen/code", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    @RateLimit(limitType = RateLimitType.USER, rate = 5, rateInterval = 60, message = "AI 对话请求过于频繁，请稍后再试")
    public Flux<ServerSentEvent<String>> chatToGenCode(@RequestParam Long appId,
                                      @RequestParam String message,
                                      HttpServletRequest request) {
        // 参数校验
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用ID无效");
        ThrowUtils.throwIf(StrUtil.isBlank(message), ErrorCode.PARAMS_ERROR, "用户消息不能为空");
        // 获取当前登录用户
        var loginUser= getLoginUserVO(request);
        // 调用服务生成代码（流式）
        var contentFlux = appService.chatToGenCode(appId, message, loginUser);
        // 转换为 ServerSentEvent格式
        return  contentFlux
                .map(chunk -> {
                    var wrapper = Map.of("d", chunk);
                    var jsonData = JSONUtil.toJsonStr(wrapper);
                    return ServerSentEvent.<String>builder()
                            .data(jsonData)
                            .build();
                })
                .concatWith(Mono.just(
                        // 发送结束事件
                        ServerSentEvent.<String>builder()
                                .event("done")
                                .data("")
                                .build()
                ));
    }

    /**
     * 应用部署
     *
     * @param appDeployRequest 部署请求
     * @param request          请求
     * @return 部署 URL
     */
    @PostMapping("/deploy")
    public BaseResponse<String> deployApp(@RequestBody AppDeployRequest appDeployRequest, HttpServletRequest request) {
        ThrowUtils.throwIf(appDeployRequest == null, ErrorCode.PARAMS_ERROR);
        var appId = appDeployRequest.getAppId();
        ThrowUtils.throwIf(appId == null || appId <= 0, ErrorCode.PARAMS_ERROR, "应用 ID 不能为空");
        // 获取当前登录用户
        var loginUser = getLoginUserVO(request);
        // 调用服务部署应用
        var deployUrl = appService.deployApp(appId, loginUser);
        return ResultUtils.success(deployUrl);
    }

    /**
     * 下载应用代码
     *
     * @param appId 应用 ID
     * @param request 请求
     * @param response 响应
     */
    @GetMapping("/download/{appId}")
    public void downloadAppCode(@PathVariable Long appId, HttpServletRequest request, HttpServletResponse response){
        // 获取当前登录用户
        var loginUser= getLoginUserVO(request);
        appService.downloadAppCode(appId, loginUser,response);
    }

    public LoginUserVO getLoginUserVO(HttpServletRequest request){
        var userObj = request.getSession().getAttribute(USER_LOGIN_STATE);
        return (LoginUserVO) userObj;
    }

}
